package org.spdata.tsdb.coder;

import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.spdata.tsdb.entity.DpsPack;
import org.spdata.tsdb.entity.Metric.ValueType;
import org.spdata.utils.ByteUtils;

/**
 * 默认编码器
 *
 */
public class DefaultDpsCoder implements TSDataCoder {
	ValueType type = null;
	public  DefaultDpsCoder (ValueType type) {
		this.type = type;
	}

	public byte[] encode(DpsPack pack) {
		if(pack.getDps().size()>0) {
			Iterator<Entry<Integer, Number>>  iter = pack.getDps().entrySet().iterator();
			Number value = iter.next().getValue();
			byte[] result = null;
			if(value instanceof Float) {
				result = this.encodeFloatDps(pack);
			}else if(value instanceof Integer) {
				result = this.encodeIntDps(pack);
			}
			return result;
		}else {
			return null;
		}
	}
	
	public DpsPack decode(byte[] input){
		int len = ByteUtils.changeBytesToInt(input[0],input[1]);
		byte[] byte1 = new byte[len];
		byte[] byte2 = new byte[input.length-len-2];
		System.arraycopy(input, 2, byte1, 0, len);
		System.arraycopy(input, 2+len, byte2, 0, byte2.length);
		IncreasingIntArrayCoder iCoder = new IncreasingIntArrayCoder();
		
		DpsPack pack = new DpsPack();
		Map<Integer,Number> dps = new LinkedHashMap<Integer,Number>();
		int[] seconds = iCoder.decode(byte1);
		List<Number> values = decodeValues(byte2,type);
		for(int i=0;i<seconds.length;i++) {
			dps.put(seconds[i], values.get(i));
		}
		pack.setDps(dps);
		return pack;
	}
	
	private List<Number> decodeValues(byte[] input,ValueType type){
		List<Number> result = null;
		if(type.equals(ValueType.intValue)) {
			IntArrayCoder coder = new IntArrayCoder();
			int[] values = coder.decode(input);
			result = NumberSeqFormatter.toList(values);
		}else if(type.equals(ValueType.floatValue)) {
			FloatArrayCoder coder = new FloatArrayCoder();
			float[] values = coder.decode(input);
			result = NumberSeqFormatter.toList(values);
		}else {
			throw new RuntimeException("this value type not yet implemented ");
		}
		return result;
	}
	
	
	private byte[] encodeIntDps(DpsPack pack) {
		int[] seconds = new int[pack.getDps().size()];
		int[] values = new int[seconds.length];
		Map<Integer,Number> dps = pack.getDps();
		int i = 0;
		Set<Entry<Integer,Number>> set = dps.entrySet();
		for(Entry<Integer,Number> entry:set) {
			int second = entry.getKey();
			Integer v = (Integer)entry.getValue();
			seconds[i] = second;
			values[i] = v;
			i++;
		}
		
		IncreasingIntArrayCoder iCoder = new IncreasingIntArrayCoder();
		IntArrayCoder vCoder = new IntArrayCoder();
		byte[] byte1 = iCoder.encode(seconds);
		byte[] byte2 = vCoder.encode(values);
		byte[] result = new byte[byte1.length+byte2.length+2];
		byte[] lenBytes = ByteUtils.changeIntTo2Bytes(byte1.length);
		System.arraycopy(lenBytes, 0, result, 0, 2);
		System.arraycopy(byte1, 0, result, 2, byte1.length);
		System.arraycopy(byte2, 0, result, 2+byte1.length, byte2.length);
		return result;
	}
	
	private byte[] encodeFloatDps(DpsPack pack) {
		int[] seconds = new int[pack.getDps().size()];
		float[] values = new float[seconds.length];
		Map<Integer,Number> dps = pack.getDps();
		int i = 0;
		Set<Entry<Integer,Number>> set = dps.entrySet();
		for(Entry<Integer,Number> entry:set) {
			int second = entry.getKey();
			Float f = (Float)entry.getValue();
			seconds[i] = second;
			values[i] = f;
			i++;
		}
		
		IncreasingIntArrayCoder iCoder = new IncreasingIntArrayCoder();
		FloatArrayCoder fCoder = new FloatArrayCoder();
		byte[] byte1 = iCoder.encode(seconds);
		byte[] byte2 = fCoder.encode(values, true);
		byte[] result = new byte[byte1.length+byte2.length+2];
		byte[] lenBytes = ByteUtils.changeIntTo2Bytes(byte1.length);
		System.arraycopy(lenBytes, 0, result, 0, 2);
		System.arraycopy(byte1, 0, result, 2, byte1.length);
		System.arraycopy(byte2, 0, result, 2+byte1.length, byte2.length);
		return result;
	}
	

}
